﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using OpenQuarters.WebQuarters.Utils;
using System.Web;

namespace OpenQuarters.WebQuarters.Core
{
    public class Resources
    {
        public static string ConcatResources(ResourceDescriptorCollection resources)
        {
            StringBuilder sb = new StringBuilder();
            if (resources != null)
            {
                foreach (var resource in resources)
                {
                    try
                    {
                        sb.AppendLine("// Start of script: " + resource.Key);

                        if (!string.IsNullOrEmpty(resource.Value.Assembly) && !string.IsNullOrEmpty(resource.Value.FileName))
                        {
                            sb.Append(new StreamReader(Resource.GetEmbeddedFile(resource.Value.Assembly, resource.Value.FilePath)).ReadToEnd());
                        }
                        else if (!string.IsNullOrEmpty(resource.Value.Source))
                        {
                            sb.AppendLine(resource.Value.Source);
                        }

                    }
                    catch (FileNotFoundException)
                    {
                        sb.AppendLine("// File not found: " + resource.Value.Assembly + ", " + resource.Value.FilePath);
                    }
                    catch (IOException)
                    {
                        sb.AppendLine("// File not found: " + resource.Value.Assembly + ", " + resource.Value.FilePath);
                    }
                    finally
                    {
                        sb.AppendLine("// End of script: " + resource.Key);
                        sb.AppendLine("");
                    }
                }
            }

            return sb.ToString();
        }

        public static void OutputResources(ResourceDescriptorCollection resources)
        {
            OutputResources(resources, null);
        }

        public static void OutputResources(ResourceDescriptorCollection resources, string resourcesETag)
        {
            if (resources.Count > 0)
            {
                var concatScripts = "";
                string eTag = null;
                var matchingETag = false;

                if (resourcesETag != null)
                {
                    eTag = resourcesETag;
                    if (Oracle.Request.Headers["If-None-Match"] != null && Oracle.Request.Headers["If-None-Match"] == eTag)
                    {
                        matchingETag = true;
                    }
                    else
                    {
                        eTag = null;
                    }
                }
                
                if (eTag == null)
                {
                    concatScripts = Resources.ConcatResources(resources);
                    if (Oracle.Request.QueryString["minify"] != null && Oracle.Request.QueryString["minify"] == "true")
                    {
                        concatScripts = Utils.Javascript.Minify(concatScripts);
                    }
                    eTag = concatScripts.MD5Encrypt();
                }

                try
                {
                    Oracle.Response.Cache.SetETag(eTag);
                }
                catch { }
                Oracle.Response.Cache.SetCacheability(HttpCacheability.Public);

                if (matchingETag)
                {
                    Oracle.Response.StatusCode = 304;
                    Oracle.Response.StatusDescription = "Not Modified";
                    Oracle.Response.End();
                }
                else
                {
                    Oracle.Response.Write(concatScripts);
                }
            }
            else
            {
                Oracle.Response.Write("// No scripts to register");
            }
        }

        public static void OutputResources(LimitedDictionary<long, ResourceDescriptorCollection> resourceCollection)
        {
            OutputResources(resourceCollection[Oracle.Request.QueryString["id"].ToInt64()]);
        }


        public static List<object> GetOptionList(string sSource)
        {
            List<object> options = new List<object>();
            var data = "";
            if (sSource.Contains("/"))
            {
                // Data has been passed in the form: Namespace.Class.MethodName/data
                data = sSource.Substring(sSource.IndexOf("/") + 1);
                sSource = sSource.Substring(0, sSource.IndexOf("/"));
            }
            Type sourceClass = GeneralUtils.GetTypeByName(sSource.Substring(0, sSource.LastIndexOf(".")));
            if (sourceClass != null)
            {
                IEnumerable sourceList = null;
                if (data.Length > 0)
                {
                    // Call the method, passing data
                    sourceList = (IEnumerable)sourceClass.GetMethod(sSource.Substring(sSource.LastIndexOf(".") + 1)).Invoke(null, new object[] { data });
                }
                else
                {
                    // Get the static property value
                    sourceList = (IEnumerable)sourceClass.GetProperty(sSource.Substring(sSource.LastIndexOf(".") + 1)).GetValue(null, null);
                }
                // Create options from returned list
                sourceList.OfType<KeyValuePair<string, string>>().ToList().ForEach(e => options.Add(new { id = e.Key, value = e.Value }));
                sourceList.OfType<string>().ToList().ForEach(e => options.Add(new { id = e, value = e }));
            }
            else
            {
                sourceClass = GeneralUtils.GetTypeByName(sSource);
                if (sourceClass != null && sourceClass.IsEnum)
                {
                    Enum.GetNames(sourceClass).ToList().ForEach(e => options.Add(new { id = e, value = Core.Translation.Translate(e.ToLower()) }));
                }
            }

            return options;
        }

        public static Dictionary<string, string> GetOptionListDictionary(string sSource)
        {
            Dictionary<string, string> options = new Dictionary<string, string>();
            var data = "";
            if (sSource.Contains("/"))
            {
                // Data has been passed in the form: Namespace.Class.MethodName/data
                data = sSource.Substring(sSource.IndexOf("/") + 1);
                sSource = sSource.Substring(0, sSource.IndexOf("/"));
            }
            Type sourceClass = GeneralUtils.GetTypeByName(sSource.Substring(0, sSource.LastIndexOf(".")));
            if (sourceClass != null)
            {
                IEnumerable sourceList = null;
                if (data.Length > 0)
                {
                    // Call the method, passing data
                    sourceList = (IEnumerable)sourceClass.GetMethod(sSource.Substring(sSource.LastIndexOf(".") + 1)).Invoke(null, new object[] { data });
                }
                else
                {
                    // Get the static property value
                    sourceList = (IEnumerable)sourceClass.GetProperty(sSource.Substring(sSource.LastIndexOf(".") + 1)).GetValue(null, null);
                }
                // Create options from returned list
                sourceList.OfType<KeyValuePair<string, string>>().ToList().ForEach(e => options.Add(e.Key, e.Value));
                sourceList.OfType<string>().ToList().ForEach(e => options.Add(e, e));
            }
            else
            {
                sourceClass = GeneralUtils.GetTypeByName(sSource);
                if (sourceClass != null && sourceClass.IsEnum)
                {
                    Enum.GetNames(sourceClass).ToList().ForEach(e => options.Add(e, Core.Translation.Translate(e.ToLower()) ));
                }
            }

            return options;
        }
    }
}
